package com.company.manage.system.service;

import com.company.manage.common.security.Encodes;
import com.company.manage.system.entity.Permission;
import com.company.manage.system.entity.ShiroUser;
import com.company.manage.system.entity.User;
import com.company.manage.system.entity.UserRole;
import com.company.manage.system.utils.CaptchaException;
import com.company.manage.system.utils.UsernamePasswordCaptchaToken;
import com.google.code.kaptcha.Constants;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;

/**
 * Created by HuangYong on 2016/1/23.
 * desc:
 */
@Service
@DependsOn({"userDao","permissionDao","rolePermissionDao"})
public class UserAuthorizingRealm extends AuthorizingRealm{
    private static final String TAG = "UserAuthorizingRealm";

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;


    /**
     * 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        ShiroUser shiroUser = (ShiroUser) principals.getPrimaryPrincipal();
        User user = userService.getUser(shiroUser.getLoginName());

        /*把principals放session中 key=userId value=principals*/
        SecurityUtils.getSubject().getSession().setAttribute(String.valueOf(user.getId()),SecurityUtils.getSubject().getPrincipals());

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        /*赋予角色*/
        for(UserRole userRole: user.getUserRoles()){
            info.addRole(userRole.getRole().getName());
        }

        /*赋予权限*/
        for(Permission permission:permissionService.getPermissions(user.getId())){
            if(StringUtils.isNotBlank(permission.getPermCode())){
                info.addStringPermission(permission.getPermCode());
            }
        }

         /*设置登录次数、时间*/
         userService.updateUserLogin(user);
        return info;

    }

    /**
     * 认证回调函数,登录时调用.
     * @param authToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authToken) throws AuthenticationException {
        UsernamePasswordCaptchaToken token = (UsernamePasswordCaptchaToken) authToken;
        User user = userService.getUser(token.getUsername());

        if(user!=null&& doCaptchaValidate(token)){
            byte[] salt = Encodes.decodeHex(user.getSalt());
            ShiroUser shiroUser = new ShiroUser(user.getId(),user.getLoginName(),user.getName());

            /*设置用户的Session*/
            Session session= SecurityUtils.getSubject().getSession();
            session.setAttribute("user",user);

            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(shiroUser, user.getPassword(), ByteSource.Util.bytes(salt), getName());
            return info;
        } else{
            return null;
        }

    }

    /**
     * 验证码校验
     * @param token
     * @return
     */
    private boolean doCaptchaValidate(UsernamePasswordCaptchaToken token) {
        String captcha = (String) SecurityUtils.getSubject().getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if(captcha!=null&& !captcha.equalsIgnoreCase(token.getCaptcha())){
            throw new CaptchaException("验证码错误!");
        }
        return true;
    }

    /**
     * 设定Password校验的Hash算法与迭代次数.
     */
    @PostConstruct
    public void initCredentialsMatcher(){
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(userService.HASH_ALGORITHM);
        matcher.setHashIterations(userService.HASH_INTERATIONS);
        setCredentialsMatcher(matcher);
    }

    public void clearAllCache() {
        clearAllCachedAuthenticationInfo();
        clearAllCachedAuthorizationInfo();
    }

    public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
        super.clearCachedAuthorizationInfo(principals);
    }

    public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
        super.clearCachedAuthenticationInfo(principals);
    }

    public void clearCache(PrincipalCollection principals) {
        super.clearCache(principals);
    }

    public void clearAllCachedAuthorizationInfo() {
        getAuthorizationCache().clear();
    }

    public void clearAllCachedAuthenticationInfo() {
        getAuthenticationCache().clear();
    }


}